home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / contrib / campbell / gsr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-27  |  36.9 KB  |  1,396 lines

  1. #define GSR_OWNER
  2. #include "gsr.h"
  3.  
  4. /*-
  5.    gnuplot Graphics Support Routines: gsr.c
  6.  
  7.    This module provides graphics routines similar to those used to
  8.    implement gnuplot.  These routines are based on (and require) the
  9.    gnuplot Graphics Terminal library (gterm.c).
  10. -*/
  11.  
  12. void plot_impulses();
  13. void plot_lines();
  14. void plot_points();
  15. void plot_dots();
  16. void edge_intersect();
  17. BOOLEAN two_edge_intersect();
  18.  
  19.  
  20. #define inrange(z,min,max) \
  21. ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  22.  
  23. /* (DFK) Watch for cancellation error near zero on axes labels */
  24. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  25. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  26. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  27.  
  28. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  29.  * macro, so I write it as a function on that machine.
  30.  */
  31. #ifndef sun386
  32. /* (DFK) Use 10^x if logscale is in effect, else x */
  33. #define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  34. #else
  35. static double CheckLog(log, x)
  36.      BOOLEAN log;
  37.      double x;
  38. {
  39.   if (log)
  40.     return(pow(10., x));
  41.   else
  42.     return(x);
  43. }
  44. #endif /* sun386 */
  45.  
  46.  
  47. static double LogScale(coord, islog, what, axis)
  48.     double coord;            /* the value */
  49.     BOOLEAN islog;            /* is this axis in logscale? */
  50.     char *what;            /* what is the coord for? */
  51.     char *axis;            /* which axis is this for ("x" or "y")? */
  52. {
  53.     if (islog) {
  54.        if (coord <= 0.0) {
  55.           char errbuf[100];        /* place to write error message */
  56.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  57.                 what, axis, coord);
  58.           (*GTterm_tbl[GTterm].text)();
  59.           (void) fflush(GSRoutfile);
  60.           int_error(errbuf, NO_CARET);
  61.        } else
  62.         return(log10(coord));
  63.     } else {
  64.        return(coord);
  65.     }
  66.     return((double)NULL); /* shut lint up */
  67. }
  68.  
  69. /* borders of plotting area */
  70. /* computed once on every call to do_plot */
  71. static boundary(scaling)
  72.     BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  73. {
  74.     register struct termentry *t = >term_tbl[GTterm];
  75.     GSRxleft = (t->h_char)*12;
  76.     GSRxright = (scaling ? 1 : GTxsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  77.     GSRybot = (t->v_char)*5/2 + 1;
  78.     GSRytop = (scaling ? 1 : GTysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  79. }
  80.  
  81.  
  82. static double dbl_raise(x,y)
  83. double x;
  84. int y;
  85. {
  86. register int i;
  87. double val;
  88.  
  89.     val = 1.0;
  90.     for (i=0; i < abs(y); i++)
  91.         val *= x;
  92.     if (y < 0 ) return (1.0/val);
  93.     return(val);
  94. }
  95.  
  96.  
  97. static double make_tics(tmin,tmax,logscale)
  98. double tmin,tmax;
  99. BOOLEAN logscale;
  100. {
  101. register double xr,xnorm,tics,tic,l10;
  102.  
  103.     xr = fabs(tmin-tmax);
  104.     
  105.     l10 = log10(xr);
  106.     if (logscale) {
  107.         tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  108.         if (tic < 1.0)
  109.             tic = 1.0;
  110.     } else {
  111.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  112.         if (xnorm <= 2)
  113.             tics = 0.2;
  114.         else if (xnorm <= 5)
  115.             tics = 0.5;
  116.         else tics = 1.0;    
  117.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  118.     }
  119.     return(tic);
  120. }
  121.  
  122.  
  123. gsr_init (fp, min_x, max_x, min_y, max_y, auto_x, auto_y, log_x, log_y)
  124. FILE *fp;
  125. double min_x, max_x;
  126. double min_y, max_y;
  127. BOOLEAN auto_x, auto_y, log_x, log_y;
  128. /*-
  129.    Initialize the internal variables used by the Gnuplot graphics support
  130.    routines.  Note that this routine should be called at least once before
  131.    any plot and at least once after changing the terminal type.
  132.  
  133.    Parameters:
  134.  
  135.            fp: Output file pointer.  This is stored as GSRoutfile (which is
  136.                the same as GToutfile) and is the stream where all the 
  137.                output for the plot is written.  If fp is different than 
  138.                GSRoutfile then the old GSRoutfile is replaced with the
  139.                new fp.  Note that the old fp is *not* closed, this is the
  140.                responsibility of the caller.  If fp is NULL the old 
  141.                GSRoutfile continues to be used.
  142.  
  143.         min_x:  Minimum x value that you intend to plot (in your own units).
  144.  
  145.         max_x:  Maximum x value that you intend to plot (in your own units).
  146.  
  147.         min_y:  Minimum y value that you intend to plot (in your own units).
  148.  
  149.         max_y:  Maximum y value that you intend to plot (in your own units).
  150.  
  151.        auto_x:  Automatically adjust the x tics to a sensible round-off point.
  152.  
  153.        auto_y:  Automatically adjust the y tics to a sensible round-off point.
  154.  
  155.         log_x:  Prepare for a logarithmic scale in the x dimension.
  156.  
  157.         log_y:  Prepare for a logarithmic scale in the y dimension.
  158.  
  159. -*/
  160. {
  161. register struct termentry *t = >term_tbl[GTterm];
  162. register int xl, yl;
  163. double xtemp, ytemp;
  164. struct text_label *this_label;
  165. struct arrow_def *this_arrow;
  166. BOOLEAN scaling;
  167.  
  168. /* Make sure a terminal has been selected. */
  169.    if (GTterm == 0) {
  170.       gt_init_terminal();
  171.       if (GTterm == 0) {
  172.         int_error ("GTterm is 0--have you defined the variable GNUTERM?");
  173.       }
  174.    }
  175.  
  176. /* Take care of GSRoutfile. */
  177.    if (fp == NULL) {
  178.       if (GSRoutfile == NULL) {
  179.          int_error("GSRoutfile NULL--gsr_init needs a file pointer!",NO_CARET);
  180.       }
  181.    }
  182.    else {
  183.       GSRoutfile = fp;
  184.    }
  185.  
  186. /* store these in variables global to this file */
  187. /* otherwise, we have to pass them around a lot */
  188.     GSRxmin = min_x;
  189.     GSRxmax = max_x; 
  190.       GSRymin = min_y;
  191.     GSRymax = max_y;
  192.         GSRlogx = log_x;
  193.         GSRlogy = log_y;
  194.  
  195. /* SETUP RANGES, SCALES AND TIC PLACES */
  196.     GSRytic = make_tics(GSRymin,GSRymax,GSRlogy);
  197.     
  198.    if (auto_y) {
  199.       if (GSRymin < GSRymax) {
  200.          GSRymin = GSRytic * floor(GSRymin/GSRytic);       
  201.          GSRymax = GSRytic * ceil(GSRymax/GSRytic);
  202.       }
  203.       else {            /* reverse axis */
  204.          GSRymin = GSRytic * ceil(GSRymin/GSRytic);       
  205.          GSRymax = GSRytic * floor(GSRymax/GSRytic);
  206.        }
  207.     }
  208.  
  209.     GSRxtic = make_tics(GSRxmin,GSRxmax,GSRlogx);
  210.        
  211.     if (auto_x) {
  212.         if (GSRxmin < GSRxmax) {
  213.             GSRxmin = GSRxtic * floor(GSRxmin/GSRxtic);    
  214.             GSRxmax = GSRxtic * ceil(GSRxmax/GSRxtic);
  215.       } else {
  216.             GSRxmin = GSRxtic * ceil(GSRxmin/GSRxtic);
  217.             GSRxmax = GSRxtic * floor(GSRxmax/GSRxtic);    
  218.        }
  219.     }
  220.  
  221. /*    This was GSRxmax == GSRxmin, but that caused an infinite loop once. */
  222.     if (fabs(GSRxmax - GSRxmin) < ZERO)
  223.         int_error("GSRxmin should not equal GSRxmax!",NO_CARET);
  224.     if (fabs(GSRymax - GSRymin) < ZERO)
  225.         int_error("GSRymin should not equal GSRymax!",NO_CARET);
  226.  
  227. /* INITIALIZE TERMINAL */
  228.     if (!GTterm_init) {
  229.         (*t->init)();
  230.         GTterm_init = TRUE;
  231.     }
  232.     scaling = (*t->scale)(GTxsize, GTysize);
  233.  
  234.      /* now compute boundary for plot (GSRxleft, GSRxright, GSRytop, GSRybot) */
  235.      boundary(scaling);
  236.  
  237. /* SCALE FACTORS  (gsr_map_x & y will now be ready to use) */
  238.     GSRyscale = (GSRytop - GSRybot)/(GSRymax - GSRymin);
  239.     GSRxscale = (GSRxright - GSRxleft)/(GSRxmax - GSRxmin);
  240. }
  241.     
  242. gsr_graphics()
  243. /*-
  244.    Routine to call the proper terminal t->graphics() routine.  This
  245.    should be called prior to trying to draw anything on the graphics
  246.    terminal.
  247. -*/
  248. {
  249. register struct termentry *t = >term_tbl[GTterm];
  250.  
  251.     (*t->graphics)();
  252. }
  253.  
  254.  
  255. gsr_reset_terminal ()
  256. /*-
  257.    Do what has to be done to reset the terminal after we are all
  258.    done plotting.  (Mostly just call (*t->reset).)
  259. -*/
  260. {
  261.    struct termentry *t = >term_tbl[GTterm];
  262.  
  263.    (*t->reset)();
  264. #ifdef VMS
  265.    vms_reset();
  266. #endif
  267. }
  268.  
  269.  
  270. gsr_draw_axis (xloc, yloc, visible)
  271. double xloc, yloc;
  272. int visible;
  273. /*-
  274.    Routine to draw axis lines (with linetype -1).  A horizontal line
  275.    will be drawn at xloc and a vertical line at yloc.  Normal usage
  276.    is for xloc and yloc to be 0.0  Note that the yloc value is also
  277.    used as the line to draw impulses on for plotting IMPULSE style
  278.    curves.  If ``visible'' is 0 then the lines won't be drawn, but
  279.    GSRxaxis_y will be computed and saved for use with IMPULSE plots.
  280.  
  281.    Parameters:
  282.  
  283.          xloc:  Location (in user coordinates) of x axis line.
  284.  
  285.          yloc:  Location (in user coordinates) of y axis line.
  286.  
  287.       visible:  0 - neither axis is drawn, 
  288.                 1 - x axis only is drawn,
  289.                 2 - y axis only is drawn,
  290.                 3 - both axis are drawn.
  291.  
  292. -*/
  293. {
  294. /* DRAW AXES */
  295. register struct termentry *t = >term_tbl[GTterm];
  296. register int xaxis_y, yaxis_x;
  297.  
  298. /* Do we need to store linetype between each of these? */
  299.     xaxis_y = gsr_map_y(xloc);
  300.     yaxis_x = gsr_map_x(yloc); 
  301.  
  302.     if (visible) 
  303.         (*t->linetype)(-1);    /* axis line type */
  304.  
  305.     if (xaxis_y < GSRybot)
  306.         xaxis_y = GSRybot;                /* save for impulse plotting */
  307.     else if (xaxis_y >= GSRytop)
  308.         xaxis_y = GSRytop ;
  309.     else if ((visible & 1) && !GSRlogy) {
  310.         (*t->move)(GSRxleft,xaxis_y);
  311.         (*t->vector)(GSRxright,xaxis_y);
  312.     }
  313.  
  314.     if ((visible & 2) && !GSRlogx && 
  315.                 yaxis_x >= GSRxleft && yaxis_x < GSRxright ) {
  316.         (*t->move)(yaxis_x,GSRybot);
  317.         (*t->vector)(yaxis_x,GSRytop);
  318.     }
  319.     GSRxaxis_y = xaxis_y;
  320. }
  321.  
  322.  
  323. gsr_set_tic_format (xformat, yformat)
  324. char *xformat, *yformat;
  325. /*-
  326.    Routine to change the x and y tic mark formats (GSRxformat and GSRyformat)
  327.    the default for both is "%g".
  328.  
  329.    Parameter:
  330.  
  331.      xformat:  Pointer to new sprintf GSRxformat string;
  332.  
  333.      yformat:  Pointer to new sprintf GSRyformat string;
  334. -*/
  335. {
  336.    GSRxformat = xformat;
  337.    GSRyformat = yformat;
  338. }
  339.  
  340.  
  341. gsr_draw_tics (xtics, xgrid, xtic_in, ytics, ygrid, ytic_in)
  342. int xtics, xgrid, xtic_in, ytics, ygrid, ytic_in;
  343. /*-
  344.    Routine to draw and label the tic marks.
  345.  
  346.    Parameters:
  347.  
  348.         xtics:  If 1 draw x axis tics, if 0 don't.
  349.  
  350.         xgrid:  If 1 draw an x grid, if 0 don't.
  351.  
  352.       xtic_in:  If 1 draw the x tics inward, if 0 don't.
  353.  
  354.         ytics:  If 1 draw y axis tics, if 0 don't.
  355.  
  356.         ygrid:  If 1 draw a y grid, if 0 don't.
  357.  
  358.       ytic_in:  If 1 draw the y tics inward, if 0 don't.
  359. -*/
  360. {
  361. #define TIC_COMPUTED 1
  362. register struct termentry *t = >term_tbl[GTterm];
  363. int type=TIC_COMPUTED;
  364.  
  365. /* 
  366.    This routine can be improved by allowing for TIC_SERIES and TIC_USER
  367.    as is done in the main gnuplot package.
  368. */
  369.    
  370. /* DRAW TICS */
  371.     (*t->linetype)(-2); /* border linetype */
  372.  
  373.     /* label y axis tics */
  374.      if (ytics) {
  375.         switch (type) {
  376.            case TIC_COMPUTED: {
  377.                if (GSRymin < GSRymax)
  378.                 draw_ytics(GSRytic * floor(GSRymin/GSRytic),
  379.                         GSRytic,
  380.                         GSRytic * ceil(GSRymax/GSRytic), ygrid, ytic_in);
  381.               else
  382.                 draw_ytics(GSRytic * floor(GSRymax/GSRytic),
  383.                         GSRytic,
  384.                         GSRytic * ceil(GSRymin/GSRytic), ygrid, ytic_in);
  385.  
  386.               break;
  387.            }
  388. #ifdef NOTUSED_YET
  389.            case TIC_SERIES: {
  390.               draw_ytics(yticdef.def.series.start, 
  391.                       yticdef.def.series.incr, 
  392.                       yticdef.def.series.end, ygrid, ytic_in);
  393.               break;
  394.            }
  395.            case TIC_USER: {
  396.               draw_user_ytics(yticdef.def.user, ygrid, ytic_in);
  397.               break;
  398.            }
  399. #endif
  400.            default: {
  401.               (*t->text)();
  402.                 (void) fflush(GSRoutfile);
  403.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  404.               break;        /* NOTREACHED */
  405.            }
  406.         }
  407.     }
  408.  
  409.     /* label x axis tics */
  410.      if (xtics) {
  411.         switch (type) {
  412.            case TIC_COMPUTED: {
  413.                if (GSRxmin < GSRxmax)
  414.                 draw_xtics(GSRxtic * floor(GSRxmin/GSRxtic),
  415.                         GSRxtic,
  416.                         GSRxtic * ceil(GSRxmax/GSRxtic), xgrid, xtic_in);
  417.               else
  418.                 draw_xtics(GSRxtic * floor(GSRxmax/GSRxtic),
  419.                         GSRxtic,
  420.                         GSRxtic * ceil(GSRxmin/GSRxtic), xgrid, xtic_in);
  421.  
  422.               break;
  423.            }
  424. #ifdef NOTUSED_YET
  425.            case TIC_SERIES: {
  426.               draw_xtics(xticdef.def.series.start, 
  427.                       xticdef.def.series.incr, 
  428.                       xticdef.def.series.end, xgrid, xtic_in);
  429.               break;
  430.            }
  431.            case TIC_USER: {
  432.               draw_user_xtics(xticdef.def.user, xgrid, xtic_in);
  433.               break;
  434.            }
  435. #endif
  436.            default: {
  437.               (*t->text)();
  438.               (void) fflush(GSRoutfile);
  439.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  440.               break;        /* NOTREACHED */
  441.            }
  442.         }
  443.     }
  444. }
  445.  
  446.  
  447. gsr_boundary ()
  448. /*-
  449.    Routine to draw the boundary (border around the plot area).
  450. -*/
  451. {
  452.  
  453. /* DRAW PLOT BORDER */
  454. register struct termentry *t = >term_tbl[GTterm];
  455.     (*t->linetype)(-2); /* border linetype */
  456.     (*t->move)(GSRxleft,GSRybot);    
  457.     (*t->vector)(GSRxright,GSRybot);    
  458.     (*t->vector)(GSRxright,GSRytop);    
  459.     (*t->vector)(GSRxleft,GSRytop);    
  460.     (*t->vector)(GSRxleft,GSRybot);
  461. }
  462.  
  463. gsr_ylabel (ylabel)
  464. char *ylabel;
  465. /*-
  466.    Routine to write a text lable for the y-axis.  Some terminal
  467.    drivers will write this as vertically oriented text.  LaTeX
  468.    will center the horizontal text on the left side of the plot.
  469.  
  470.    Parameter:
  471.  
  472.       ylabel:  Text string to place as the y axis label.
  473. -*/
  474. {
  475. /* PLACE YLABEL */
  476. register struct termentry *t = >term_tbl[GTterm];
  477.     if (*ylabel != NULL) {
  478.        if ((*t->text_angle)(1)) { 
  479.           if ((*t->justify_text)(CENTRE)) { 
  480.              (*t->put_text)((t->v_char),
  481.                          (GSRytop+GSRybot)/2, ylabel);
  482.           }
  483.           else {
  484.              (*t->put_text)((t->v_char),
  485.                          (GSRytop+GSRybot)/2-(t->h_char)*strlen(ylabel)/2, 
  486.                          ylabel);
  487.           }
  488.        }
  489.        else {
  490.           (void)(*t->justify_text)(LEFT);
  491.           (*t->put_text)(0,GSRytop+(t->v_char), ylabel);
  492.        }
  493.        (void)(*t->text_angle)(0);
  494.     }
  495. }
  496.  
  497.  
  498. gsr_xlabel (xlabel)
  499. char *xlabel;
  500. /*-
  501.    Routine to write a text label for the x-axis.  
  502.  
  503.    Parameter:
  504.  
  505.       xlabel:  Text string to place as the x axis label.
  506. -*/
  507. {
  508.  
  509. /* PLACE XLABEL */
  510. register struct termentry *t = >term_tbl[GTterm];
  511.     if (*xlabel != NULL) {
  512.        if ((*t->justify_text)(CENTRE)) 
  513.         (*t->put_text)( (GSRxleft+GSRxright)/2,
  514.                     GSRybot-2*(t->v_char), xlabel);
  515.        else
  516.         (*t->put_text)( (GSRxleft+GSRxright)/2 - strlen(xlabel)*(t->h_char)/2,
  517.                     GSRybot-2*(t->v_char), xlabel);
  518.     }
  519. }
  520.  
  521. gsr_title (title)
  522. char *title;
  523. /*-
  524.    Routine to write a title at the top of the plot.  
  525.  
  526.    Parameter:
  527.  
  528.        title:  Text string to place as the title for the plot.
  529. -*/
  530. {
  531. /* PLACE TITLE */
  532. register struct termentry *t = >term_tbl[GTterm];
  533.     if (*title != NULL) {
  534.        if ((*t->justify_text)(CENTRE)) 
  535.         (*t->put_text)( (GSRxleft+GSRxright)/2, 
  536.                     GSRytop+(t->v_char), title);
  537.        else
  538.         (*t->put_text)( (GSRxleft+GSRxright)/2 - strlen(title)*(t->h_char)/2,
  539.                     GSRytop+(t->v_char), title);
  540.     }
  541. }
  542.  
  543.  
  544. gsr_label (x, y, text, justify, position)
  545. double x,y;
  546. char *text;
  547. BOOLEAN justify;
  548. int position;
  549. /*-
  550.     Routine to place a label (text string) at (x,y) where (x,y) is in user
  551.     coordinates.
  552.  
  553.     Parameters:
  554.  
  555.              x: user coordinate x location for text string.
  556.  
  557.              y: user coordinate y location for text string.
  558.  
  559.           text: Text to plot at this location.
  560.  
  561.        justify: Flag indicating if text is to be justified in place:
  562.                 0 - don't justify
  563.                 1 - justify (if terminal device can do so).
  564.  
  565.       position: From gtplot.h, one of LEFT, CENTRE, RIGHT 
  566. -*/
  567. {
  568. /* PLACE LABELS */
  569. double xtemp, ytemp;
  570. register struct termentry *t = >term_tbl[GTterm];
  571.     xtemp = LogScale(x, GSRlogx, "label", "x");
  572.     ytemp = LogScale(y, GSRlogy, "label", "y");
  573.     if ((*t->justify_text)(position)) {
  574.         (*t->put_text)(gsr_map_x(xtemp),gsr_map_y(ytemp),text);
  575.     }
  576.     else {
  577.         switch(position) {
  578.             case  LEFT:
  579.                 (*t->put_text)(gsr_map_x(xtemp),gsr_map_y(ytemp), text);
  580.             break;
  581.             case CENTRE:
  582.                 (*t->put_text)(gsr_map_x(xtemp)-(t->h_char)*strlen(text)/2,
  583.                     gsr_map_y(ytemp), text);
  584.             break;
  585.             case RIGHT:
  586.                 (*t->put_text)(gsr_map_x(xtemp)-(t->h_char)*strlen(text),
  587.                         gsr_map_y(ytemp), text);
  588.             break;
  589.          }
  590.      }
  591. }
  592.  
  593.  
  594. gsr_arrow (start_x, start_y, end_x, end_y)
  595. double start_x, start_y, end_x, end_y;
  596. /*-
  597.     Draw an arrow from (start_x,start_y) to (end_x,end_y).
  598.  
  599.     Parameters:
  600.  
  601.        start_x:  starting x coordinate in user coordinates.
  602.  
  603.        start_y:  starting y coordinate in user coordinates.
  604.  
  605.          end_x:  ending x coordinate in user coordinates.
  606.  
  607.          end_y:  ending y coordinate in user coordinates.
  608. -*/
  609. {
  610. /* PLACE ARROWS */
  611. register struct termentry *t = >term_tbl[GTterm];
  612.        int sx = gsr_map_x(LogScale(start_x, GSRlogx, "arrow", "x"));
  613.        int sy = gsr_map_y(LogScale(start_y, GSRlogy, "arrow", "y"));
  614.        int ex = gsr_map_x(LogScale(end_x, GSRlogx, "arrow", "x"));
  615.        int ey = gsr_map_y(LogScale(end_y, GSRlogy, "arrow", "y"));
  616.  
  617.     (*t->linetype)(0);    /* arrow line type */
  618.        
  619.        (*t->arrow)(sx, sy, ex, ey);
  620. }
  621.  
  622.  
  623. gsr_curve (style, points, npoints)
  624. int style, npoints;
  625. struct coordinate *points;
  626. /*-
  627.    Routine to draw the curve located in the array points to the device.
  628.  
  629.    Parameters:
  630.  
  631.         style: One of IMPULSES, LINES, POINTS, LINESPOINTS, or DOTS from
  632.                gtplot.h
  633.  
  634.        points: An array of npoints coordinates, where struct coordinate
  635.                is defined in gtplot.h.
  636.  
  637.       npoints: Number of points to plot out of the points array.
  638. -*/
  639. {
  640. register struct termentry *t = >term_tbl[GTterm];
  641. /* DRAW CURVES */
  642.         switch(style) {
  643.             case IMPULSES: 
  644.                plot_impulses(points, npoints, GSRxaxis_y);
  645.            break;
  646.             case LINES: 
  647.                plot_lines(points, npoints);
  648.             break;
  649.             case POINTS: 
  650.                plot_points(points, npoints);
  651.                break;
  652.             case LINESPOINTS: 
  653.                /* put lines */
  654.                plot_lines(points, npoints);
  655.  
  656.                /* put points */
  657.                plot_points(points, npoints);
  658.             break;
  659.             case DOTS: 
  660.                plot_dots(points, npoints);
  661.             break;
  662.             default:
  663.               (*t->text)();
  664.               (void) fflush(GSRoutfile);
  665.               int_error("unknown style in gsr_points", NO_CARET);
  666.               break;        /* NOTREACHED */
  667.         }
  668. }
  669.  
  670.  
  671. gsr_text()
  672. /*- 
  673.    Routine to call the appropriate terminal _text() routine.  This works
  674.    together with gsr_graphics() to go in and out of graphics mode: 
  675.  
  676.       gsr_graphics(); ... plot routines ...  gsr_text();
  677.  
  678.    On many terminal devices this must be called before any of the plot 
  679.    will show up on the device.
  680. -*/
  681. {
  682. register struct termentry *t = >term_tbl[GTterm];
  683.  
  684.     (*t->text)();
  685.     (void) fflush(GSRoutfile);
  686. }
  687.  
  688.  
  689. gsr_line_point_type (line_type, point_type)
  690. /*-
  691.    Routine to select (ahead of gsr_curve()) the line_type or point_type
  692.    that you wish to use.
  693.  
  694.    Parameters:
  695.  
  696.     line_type:  The desired line type (from -2 - 12), the exact range
  697.                 depends upon the term device in use.
  698.  
  699.    point_type:  The desired point type (from -1 - 6) the exact range
  700.                 depends upon the term device in use.
  701. -*/
  702. {
  703.    struct termentry *t = >term_tbl[GTterm];
  704.  
  705. /* Record both requests. */
  706.    GSRpoint_type = point_type;
  707.    GSRline_type = line_type;
  708.  
  709. /* Actually set the line_type request. */
  710.    (*t->linetype)(line_type);
  711. }
  712.    
  713.  
  714. #define OUTRANGE   0
  715. #define INRANGE    1
  716. #define UNDEFINED -1
  717.  
  718. /* plot_impulses:
  719.  * Plot the curves in IMPULSES style
  720.  */
  721. static void
  722. plot_impulses(points, npoints, xaxis_y)
  723.     struct coordinate *points;
  724.     int xaxis_y;
  725. {
  726.     int i;
  727.     int x,y;
  728.     int type;
  729.     struct termentry *t = >term_tbl[GTterm];
  730.  
  731.     for (i = 0; i < npoints; i++) {
  732.        type = inrange (points[i].x, GSRxmin, GSRxmax) &&
  733.                                     inrange (points[i].y, GSRymin, GSRymax);
  734.        switch (type) {
  735.           case INRANGE: {
  736.              x = gsr_map_x(points[i].x);
  737.              y = gsr_map_y(points[i].y);
  738.              break;
  739.           }
  740.           case OUTRANGE: {
  741.              if (!inrange(points[i].x, GSRxmin,GSRxmax))
  742.                continue;
  743.              x = gsr_map_x(points[i].x);
  744.              if ((GSRymin < GSRymax && points[i].y < GSRymin)
  745.                 || (GSRymax < GSRymin && points[i].y > GSRymin))
  746.                y = gsr_map_y(GSRymin);
  747.              if ((GSRymin < GSRymax && points[i].y > GSRymax)
  748.                 || (GSRymax<GSRymin && points[i].y < GSRymax))
  749.                y = gsr_map_y(GSRymax);
  750.              break;
  751.           }
  752.           default:        /* just a safety */
  753.           case UNDEFINED: {
  754.              continue;
  755.           }
  756.        }
  757.                     
  758.        (*t->move)(x,xaxis_y);
  759.        (*t->vector)(x,y);
  760.     }
  761.  
  762. }
  763.  
  764. /* plot_lines:
  765.  * Plot the curves in LINES style
  766.  */
  767. static void
  768. plot_lines(points, npoints)
  769.     struct coordinate *points;
  770.     int npoints;
  771. {
  772.     int i;                /* point index */
  773.     int x,y;                /* point in terminal coordinates */
  774.     int type;
  775.     int clip_lines1 = 0,  /* Not used yet. */
  776.         clip_lines2 = 0;
  777.     struct termentry *t = >term_tbl[GTterm];
  778.     enum coord_type prev = UNDEFINED; /* type of previous point */
  779.     double ex, ey;            /* an edge point */
  780.     double lx[2], ly[2];        /* two edge points */
  781.  
  782.     for (i = 0; i < npoints; i++) {
  783.        type = inrange (points[i].x, GSRxmin, GSRxmax) &&
  784.                                     inrange (points[i].y, GSRymin, GSRymax);
  785.        switch (type) {
  786.           case INRANGE: {
  787.              x = gsr_map_x(points[i].x);
  788.              y = gsr_map_y(points[i].y);
  789.  
  790.              if (prev == INRANGE) {
  791.                 (*t->vector)(x,y);
  792.              } else if (prev == OUTRANGE) {
  793.                 /* from outrange to inrange */
  794.                 if (!clip_lines1) {
  795.                     (*t->move)(x,y);
  796.                 } else {
  797.                     edge_intersect(points, i, &ex, &ey);
  798.                     (*t->move)(gsr_map_x(ex), gsr_map_y(ey));
  799.                     (*t->vector)(x,y);
  800.                 }
  801.              } else {        /* prev == UNDEFINED */
  802.                 (*t->move)(x,y);
  803.                 (*t->vector)(x,y);
  804.              }
  805.                     
  806.              break;
  807.           }
  808.           case OUTRANGE: {
  809.              if (prev == INRANGE) {
  810.                 /* from inrange to outrange */
  811.                 if (clip_lines1) {
  812.                     edge_intersect(points, i, &ex, &ey);
  813.                     (*t->vector)(gsr_map_x(ex), gsr_map_y(ey));
  814.                 }
  815.              } else if (prev == OUTRANGE) {
  816.                 /* from outrange to outrange */
  817.                 if (clip_lines2) {
  818.                     if (two_edge_intersect(points, i, lx, ly)) {
  819.                        (*t->move)(gsr_map_x(lx[0]), gsr_map_y(ly[0]));
  820.                        (*t->vector)(gsr_map_x(lx[1]), gsr_map_y(ly[1]));
  821.                     }
  822.                 }
  823.              }
  824.              break;
  825.           }
  826.           default:        /* just a safety */
  827.           case UNDEFINED: {
  828.              break;
  829.           }
  830.        }
  831.        prev = type;
  832.     }
  833. }
  834.  
  835. /* plot_points:
  836.  * Plot the curves in POINTS style
  837.  */
  838. static void
  839. plot_points(points, npoints)
  840.     struct coordinate *points;
  841.     int npoints;
  842. {
  843.     int i;
  844.     int x,y;
  845.     int type;
  846.     struct termentry *t = >term_tbl[GTterm];
  847.  
  848.     for (i = 0; i < npoints; i++) {
  849.        type = inrange (points[i].x, GSRxmin, GSRxmax) &&
  850.                                     inrange (points[i].y, GSRymin, GSRymax);
  851.        if (type == INRANGE) {
  852.           x = gsr_map_x(points[i].x);
  853.           y = gsr_map_y(points[i].y);
  854.           /* do clipping (was ...if necessary...) */
  855.           if (   x >= GSRxleft + t->h_tic  && y >= GSRybot + t->v_tic 
  856.               && x <= GSRxright - t->h_tic && y <= GSRytop - t->v_tic)
  857.             (*t->point)(x,y, GSRpoint_type);
  858.        }
  859.     }
  860. }
  861.  
  862. /* plot_dots:
  863.  * Plot the curves in DOTS style
  864.  */
  865. static void
  866. plot_dots(points, npoints)
  867.     struct coordinate *points;
  868.     int npoints;
  869. {
  870.     int i;
  871.     int x,y;
  872.     int type;
  873.     struct termentry *t = >term_tbl[GTterm];
  874.  
  875.     for (i = 0; i < npoints; i++) {
  876.        type = inrange (points[i].x, GSRxmin, GSRxmax) &&
  877.                                     inrange (points[i].y, GSRymin, GSRymax);
  878.        if (type == INRANGE) {
  879.           x = gsr_map_x(points[i].x);
  880.           y = gsr_map_y(points[i].y);
  881.           /* point type -1 is a dot */
  882.           (*t->point)(x,y, -1);
  883.        }
  884.     }
  885. }
  886.  
  887.  
  888. /* single edge intersection algorithm */
  889. /* Given two points, one inside and one outside the plot, return
  890.  * the point where an edge of the plot intersects the line segment defined 
  891.  * by the two points.
  892.  */
  893. static void
  894. edge_intersect(points, i, ex, ey)
  895.     struct coordinate *points; /* the points array */
  896.     int i;                /* line segment from point i-1 to point i */
  897.     double *ex, *ey;        /* the point where it crosses an edge */
  898. {
  899.     /* global xmin, xmax, ymin, xmax */
  900.     double ax = points[i-1].x;
  901.     double ay = points[i-1].y;
  902.     double bx = points[i].x;
  903.     double by = points[i].y;
  904.     double x, y;            /* possible intersection point */
  905.  
  906.     if (by == ay) {
  907.        /* horizontal line */
  908.        /* assume inrange(by, GSRymin, GSRymax) */
  909.        *ey = by;        /* == ay */
  910.  
  911.        if (inrange(GSRxmax, ax, bx))
  912.         *ex = GSRxmax;
  913.        else if (inrange(GSRxmin, ax, bx))
  914.         *ex = GSRxmin;
  915.        else {
  916.         (*GTterm_tbl[GTterm].text)();
  917.         (void) fflush(GSRoutfile);
  918.         int_error("error in edge_intersect", NO_CARET);
  919.        }
  920.        return;
  921.     } else if (bx == ax) {
  922.        /* vertical line */
  923.        /* assume inrange(bx, GSRxmin, GSRxmax) */
  924.        *ex = bx;        /* == ax */
  925.  
  926.        if (inrange(GSRymax, ay, by))
  927.         *ey = GSRymax;
  928.        else if (inrange(GSRymin, ay, by))
  929.         *ey = GSRymin;
  930.        else {
  931.         (*GTterm_tbl[GTterm].text)();
  932.         (void) fflush(GSRoutfile);
  933.         int_error("error in edge_intersect", NO_CARET);
  934.        }
  935.        return;
  936.     }
  937.  
  938.     /* slanted line of some kind */
  939.  
  940.     /* does it intersect ymin edge */
  941.     if (inrange(GSRymin, ay, by) && GSRymin != ay && GSRymin != by) {
  942.        x = ax + (GSRymin-ay) * ((bx-ax) / (by-ay));
  943.        if (inrange(x, GSRxmin, GSRxmax)) {
  944.           *ex = x;
  945.           *ey = GSRymin;
  946.           return;            /* yes */
  947.        }
  948.     }
  949.     
  950.     /* does it intersect ymax edge */
  951.     if (inrange(GSRymax, ay, by) && GSRymax != ay && GSRymax != by) {
  952.        x = ax + (GSRymax-ay) * ((bx-ax) / (by-ay));
  953.        if (inrange(x, GSRxmin, GSRxmax)) {
  954.           *ex = x;
  955.           *ey = GSRymax;
  956.           return;            /* yes */
  957.        }
  958.     }
  959.  
  960.     /* does it intersect xmin edge */
  961.     if (inrange(GSRxmin, ax, bx) && GSRxmin != ax && GSRxmin != bx) {
  962.        y = ay + (GSRxmin-ax) * ((by-ay) / (bx-ax));
  963.        if (inrange(y, GSRymin, GSRymax)) {
  964.           *ex = GSRxmin;
  965.           *ey = y;
  966.           return;
  967.        }
  968.     }
  969.  
  970.     /* does it intersect xmax edge */
  971.     if (inrange(GSRxmax, ax, bx) && GSRxmax != ax && GSRxmax != bx) {
  972.        y = ay + (GSRxmax-ax) * ((by-ay) / (bx-ax));
  973.        if (inrange(y, GSRymin, GSRymax)) {
  974.           *ex = GSRxmax;
  975.           *ey = y;
  976.           return;
  977.        }
  978.     }
  979.  
  980.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  981.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  982.     * FALSE above. Otherwise we fall through all the tests above. 
  983.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  984.     * since either a or b must be INRANGE. 
  985.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  986.     * Handle them carefully here. As yet we have no way for them to be 
  987.     * +VERYLARGE.
  988.     */
  989.     if (ax == -VERYLARGE) {
  990.        if (ay != -VERYLARGE) {
  991.           *ex = min(GSRxmin, GSRxmax);
  992.           *ey = by;
  993.           return;
  994.        }
  995.     } else if (bx == -VERYLARGE) {
  996.        if (by != -VERYLARGE) {
  997.           *ex = min(GSRxmin, GSRxmax);
  998.           *ey = ay;
  999.           return;
  1000.        }
  1001.     } else if (ay == -VERYLARGE) {
  1002.        /* note we know ax != -VERYLARGE */
  1003.        *ex = bx;
  1004.        *ey = min(GSRymin, GSRymax);
  1005.        return;
  1006.     } else if (by == -VERYLARGE) {
  1007.        /* note we know bx != -VERYLARGE */
  1008.        *ex = ax;
  1009.        *ey = min(GSRymin, GSRymax);
  1010.        return;
  1011.     }
  1012.  
  1013.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  1014.     * or the inrange point is on the edge, and
  1015.      * the line segment from the outrange point does not cross any 
  1016.     * other edges to get there. In either case, we return the inrange 
  1017.     * point as the 'edge' intersection point. This will basically draw
  1018.     * line.
  1019.     */
  1020. /* Had to change this--just guessing this is right.  JDC */
  1021.     if (points[i].x != -VERYLARGE) {
  1022.        *ex = bx; 
  1023.        *ey = by;
  1024.     } else {
  1025.        *ex = ax; 
  1026.        *ey = ay;
  1027.     }
  1028.     return;
  1029. }
  1030.  
  1031. /* double edge intersection algorithm */
  1032. /* Given two points, both outside the plot, return
  1033.  * the points where an edge of the plot intersects the line segment defined 
  1034.  * by the two points. There may be zero, one, two, or an infinite number
  1035.  * of intersection points. (One means an intersection at a corner, infinite
  1036.  * means overlaying the edge itself). We return FALSE when there is nothing
  1037.  * to draw (zero intersections), and TRUE when there is something to 
  1038.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1039.  * not distinguish it - we draw it anyway).
  1040.  */
  1041. static BOOLEAN                /* any intersection? */
  1042. two_edge_intersect(points, i, lx, ly)
  1043.     struct coordinate *points; /* the points array */
  1044.     int i;                /* line segment from point i-1 to point i */
  1045.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1046. {
  1047.     /* global xmin, xmax, ymin, xmax */
  1048.     double ax = points[i-1].x;
  1049.     double ay = points[i-1].y;
  1050.     double bx = points[i].x;
  1051.     double by = points[i].y;
  1052.     double x, y;            /* possible intersection point */
  1053.     BOOLEAN intersect = FALSE;
  1054.  
  1055.     if (by == ay) {
  1056.        /* horizontal line */
  1057.        /* y coord must be in range, and line must span both xmin and xmax */
  1058.        /* note that spanning GSRxmin implies spanning GSRxmax */
  1059.        if (inrange(by, GSRymin, GSRymax) && inrange(GSRxmin, ax, bx)) {
  1060.           *lx++ = GSRxmin;
  1061.           *ly++ = by;
  1062.           *lx++ = GSRxmax;
  1063.           *ly++ = by;
  1064.           return(TRUE);
  1065.        } else
  1066.         return(FALSE);
  1067.     } else if (bx == ax) {
  1068.        /* vertical line */
  1069.        /* x coord must be in range, and line must span both GSRymin and GSRymax */
  1070.        /* note that spanning GSRymin implies spanning GSRymax */
  1071.        if (inrange(bx, GSRxmin, GSRxmax) && inrange(GSRymin, ay, by)) {
  1072.           *lx++ = bx;
  1073.           *ly++ = GSRymin;
  1074.           *lx++ = bx;
  1075.           *ly++ = GSRymax;
  1076.           return(TRUE);
  1077.        } else
  1078.         return(FALSE);
  1079.     }
  1080.  
  1081.     /* slanted line of some kind */
  1082.     /* there can be only zero or two intersections below */
  1083.  
  1084.     /* does it intersect GSRymin edge */
  1085.     if (inrange(GSRymin, ay, by)) {
  1086.        x = ax + (GSRymin-ay) * ((bx-ax) / (by-ay));
  1087.        if (inrange(x, GSRxmin, GSRxmax)) {
  1088.           *lx++ = x;
  1089.           *ly++ = GSRymin;
  1090.           intersect = TRUE;
  1091.        }
  1092.     }
  1093.     
  1094.     /* does it intersect GSRymax edge */
  1095.     if (inrange(GSRymax, ay, by)) {
  1096.        x = ax + (GSRymax-ay) * ((bx-ax) / (by-ay));
  1097.        if (inrange(x, GSRxmin, GSRxmax)) {
  1098.           *lx++ = x;
  1099.           *ly++ = GSRymax;
  1100.           intersect = TRUE;
  1101.        }
  1102.     }
  1103.  
  1104.     /* does it intersect GSRxmin edge */
  1105.     if (inrange(GSRxmin, ax, bx)) {
  1106.        y = ay + (GSRxmin-ax) * ((by-ay) / (bx-ax));
  1107.        if (inrange(y, GSRymin, GSRymax)) {
  1108.           *lx++ = GSRxmin;
  1109.           *ly++ = y;
  1110.           intersect = TRUE;
  1111.        }
  1112.     }
  1113.  
  1114.     /* does it intersect GSRxmax edge */
  1115.     if (inrange(GSRxmax, ax, bx)) {
  1116.        y = ay + (GSRxmax-ax) * ((by-ay) / (bx-ax));
  1117.        if (inrange(y, GSRymin, GSRymax)) {
  1118.           *lx++ = GSRxmax;
  1119.           *ly++ = y;
  1120.           intersect = TRUE;
  1121.        }
  1122.     }
  1123.  
  1124.     if (intersect)
  1125.      return(TRUE);
  1126.  
  1127.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1128.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1129.     * FALSE above.
  1130.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1131.     * Otherwise we fall through all the tests above. 
  1132.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1133.     */
  1134.     if (ax == -VERYLARGE) {
  1135.        if (ay != -VERYLARGE
  1136.           && inrange(by, GSRymin, GSRymax) && inrange(GSRxmax, ax, bx)) {
  1137.           *lx++ = GSRxmin;
  1138.           *ly = by;
  1139.           *lx++ = GSRxmax;
  1140.           *ly = by;
  1141.           intersect = TRUE;
  1142.        }
  1143.     } else if (bx == -VERYLARGE) {
  1144.        if (by != -VERYLARGE
  1145.           && inrange(ay, GSRymin, GSRymax) && inrange(GSRxmax, ax, bx)) {
  1146.           *lx++ = GSRxmin;
  1147.           *ly = ay;
  1148.           *lx++ = GSRxmax;
  1149.           *ly = ay;
  1150.           intersect = TRUE;
  1151.        }
  1152.     } else if (ay == -VERYLARGE) {
  1153.        /* note we know ax != -VERYLARGE */
  1154.        if (inrange(bx, GSRxmin, GSRxmax) && inrange(GSRymax, ay, by)) {
  1155.           *lx++ = bx;
  1156.           *ly = GSRymin;
  1157.           *lx++ = bx;
  1158.           *ly = GSRymax;
  1159.           intersect = TRUE;
  1160.        }
  1161.     } else if (by == -VERYLARGE) {
  1162.        /* note we know bx != -VERYLARGE */
  1163.        if (inrange(ax, GSRxmin, GSRxmax) && inrange(GSRymax, ay, by)) {
  1164.           *lx++ = ax;
  1165.           *ly = GSRymin;
  1166.           *lx++ = ax;
  1167.           *ly = GSRymax;
  1168.           intersect = TRUE;
  1169.        }
  1170.     }
  1171.  
  1172.     return(intersect);
  1173. }
  1174.  
  1175. /* DRAW_YTICS: draw a regular tic series, y axis */
  1176. static draw_ytics(start, incr, end, ygrid, ytic_in)
  1177. double start, incr, end; /* tic series definition */
  1178. int ygrid, ytic_in;
  1179.         /* assume start < end, incr > 0 */
  1180. {
  1181.     double ticplace;
  1182.     int ltic;            /* for mini log tics */
  1183.     double lticplace;    /* for mini log tics */
  1184.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1185.  
  1186.     if (end == VERYLARGE)            /* for user-def series */
  1187.         end = max(GSRymin,GSRymax);
  1188.  
  1189.     /* limit to right side of plot */
  1190.     end = min(end, max(GSRymin,GSRymax));
  1191.  
  1192.     /* to allow for rounding errors */
  1193.     ticmin = min(GSRymin,GSRymax) - SIGNIF*incr;
  1194.     ticmax = max(GSRymin,GSRymax) + SIGNIF*incr;
  1195.     end = end + SIGNIF*incr; 
  1196.  
  1197.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1198.         if ( inrange(ticplace,ticmin,ticmax) )
  1199.             ytick(ticplace, GSRyformat, incr, 1.0, ygrid, ytic_in);
  1200.         if (GSRlogy && incr == 1.0) {
  1201.             /* add mini-ticks to log scale ticmarks */
  1202.             for (ltic = 2; ltic <= 9; ltic++) {
  1203.                 lticplace = ticplace+log10((double)ltic);
  1204.                 if ( inrange(lticplace,ticmin,ticmax) )
  1205.                     ytick(lticplace, (char *)NULL, incr, 0.5, ygrid, ytic_in);
  1206.             }
  1207.         }
  1208.     }
  1209. }
  1210.  
  1211.  
  1212. /* DRAW_XTICS: draw a regular tic series, x axis */
  1213. static draw_xtics(start, incr, end, xgrid, xtic_in)
  1214. double start, incr, end; /* tic series definition */
  1215. int xgrid, xtic_in;
  1216.         /* assume start < end, incr > 0 */
  1217. {
  1218.     double ticplace;
  1219.     int ltic;            /* for mini log tics */
  1220.     double lticplace;    /* for mini log tics */
  1221.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1222.  
  1223.     if (end == VERYLARGE)            /* for user-def series */
  1224.         end = max(GSRxmin,GSRxmax);
  1225.  
  1226.     /* limit to right side of plot */
  1227.     end = min(end, max(GSRxmin,GSRxmax));
  1228.  
  1229.     /* to allow for rounding errors */
  1230.     ticmin = min(GSRxmin,GSRxmax) - SIGNIF*incr;
  1231.     ticmax = max(GSRxmin,GSRxmax) + SIGNIF*incr;
  1232.     end = end + SIGNIF*incr; 
  1233.  
  1234.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1235.         if ( inrange(ticplace,ticmin,ticmax) )
  1236.             xtick(ticplace, GSRxformat, incr, 1.0, xgrid, xtic_in);
  1237.         if (GSRlogx && incr == 1.0) {
  1238.             /* add mini-ticks to log scale ticmarks */
  1239.             for (ltic = 2; ltic <= 9; ltic++) {
  1240.                 lticplace = ticplace+log10((double)ltic);
  1241.                 if ( inrange(lticplace,ticmin,ticmax) )
  1242.                     xtick(lticplace, (char *)NULL, incr, 0.5, xgrid, xtic_in);
  1243.             }
  1244.         }
  1245.     }
  1246. }
  1247.  
  1248. #ifdef NOTUSED_YET
  1249. /* DRAW_USER_YTICS: draw a user tic series, y axis */
  1250. static draw_user_ytics(list, ygrid, ytic_in)
  1251. struct ticmark *list;    /* list of tic marks */
  1252. int ygrid, ytic_in;
  1253. {
  1254.     double ticplace;
  1255.     double incr = (GSRymax - GSRymin) / 10;
  1256.     /* global GSRxmin, GSRxmax, xscale, GSRymin, GSRymax, yscale */
  1257.  
  1258.     while (list != NULL) {
  1259.        ticplace = list->position;
  1260.        if ( inrange(ticplace, GSRymin, GSRymax)         /* in range */
  1261.           || NearlyEqual(ticplace, GSRymin, incr)    /* == GSRymin */
  1262.           || NearlyEqual(ticplace, GSRymax, incr))    /* == GSRymax */
  1263.         ytick(ticplace, list->label, incr, 1.0, ygrid, ytic_in);
  1264.  
  1265.        list = list->next;
  1266.     }
  1267. }
  1268. #endif
  1269.  
  1270. #ifdef NOTUSED_YET
  1271. /* DRAW_USER_XTICS: draw a user tic series, x axis */
  1272. static draw_user_xtics(list, xgrid, xtic_in)
  1273. struct ticmark *list;    /* list of tic marks */
  1274. int xgrid, xtic_in;
  1275. {
  1276.     double ticplace;
  1277.     double incr = (GSRxmax - GSRxmin) / 10;
  1278.     /* global GSRxmin, GSRxmax, xscale, GSRymin, GSRymax, yscale */
  1279.  
  1280.     while (list != NULL) {
  1281.        ticplace = list->position;
  1282.        if ( inrange(ticplace, GSRxmin, GSRxmax)         /* in range */
  1283.           || NearlyEqual(ticplace, GSRxmin, incr)    /* == GSRxmin */
  1284.           || NearlyEqual(ticplace, GSRxmax, incr))    /* == GSRxmax */
  1285.         xtick(ticplace, list->label, incr, 1.0, xgrid, xtic_in);
  1286.  
  1287.        list = list->next;
  1288.     }
  1289. }
  1290. #endif
  1291.  
  1292. /* draw and label a y-axis ticmark */
  1293. static ytick(place, text, spacing, ticscale, ygrid, ytic_in)
  1294. double place;                   /* where on axis to put it */
  1295. char *text;                     /* optional text label */
  1296. double spacing;         /* something to use with checkzero */
  1297. float ticscale;         /* scale factor for tic mark (0..1] */
  1298. int ygrid, ytic_in;
  1299. {
  1300.     register struct termentry *t = >term_tbl[GTterm];
  1301.     char ticlabel[101];
  1302.     int ticsize = (int)((t->h_tic) * ticscale);
  1303.  
  1304.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1305.     if (ygrid) {
  1306.            (*t->linetype)(-1);  /* axis line type */
  1307.            (*t->move)(GSRxleft, gsr_map_y(place));
  1308.            (*t->vector)(GSRxright, gsr_map_y(place));
  1309.            (*t->linetype)(-2); /* border linetype */
  1310.     }
  1311.     if (ytic_in) {
  1312.            (*t->move)(GSRxleft, gsr_map_y(place));
  1313.            (*t->vector)(GSRxleft + ticsize, gsr_map_y(place));
  1314.            (*t->move)(GSRxright, gsr_map_y(place));
  1315.            (*t->vector)(GSRxright - ticsize, gsr_map_y(place));
  1316.     } else {
  1317.            (*t->move)(GSRxleft, gsr_map_y(place));
  1318.            (*t->vector)(GSRxleft - ticsize, gsr_map_y(place));
  1319.     }
  1320.  
  1321.     /* label the ticmark */
  1322.     if (text) {
  1323.         (void) sprintf(ticlabel, text, CheckLog(GSRlogy, place));
  1324.         if ((*t->justify_text)(RIGHT)) {
  1325.            (*t->put_text)(GSRxleft-(t->h_char),
  1326.                        gsr_map_y(place), ticlabel);
  1327.         } else {
  1328.            (*t->put_text)(GSRxleft-(t->h_char)*(strlen(ticlabel)+1),
  1329.                        gsr_map_y(place), ticlabel);
  1330.         }
  1331.     }
  1332. }
  1333.  
  1334. /* draw and label an x-axis ticmark */
  1335. static xtick(place, text, spacing, ticscale, xgrid, xtic_in)
  1336. double place;                   /* where on axis to put it */
  1337. char *text;                     /* optional text label */
  1338. double spacing;         /* something to use with checkzero */
  1339. float ticscale;         /* scale factor for tic mark (0..1] */
  1340. int xgrid, xtic_in;
  1341. {
  1342.     register struct termentry *t = >term_tbl[GTterm];
  1343.     char ticlabel[101];
  1344.     int ticsize = (int)((t->v_tic) * ticscale);
  1345.  
  1346.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1347.     if (xgrid) {
  1348.            (*t->linetype)(-1);  /* axis line type */
  1349.            (*t->move)(gsr_map_x(place), GSRybot);
  1350.            (*t->vector)(gsr_map_x(place), GSRytop);
  1351.            (*t->linetype)(-2); /* border linetype */
  1352.     }
  1353.     if (xtic_in) {
  1354.            (*t->move)(gsr_map_x(place), GSRybot);
  1355.            (*t->vector)(gsr_map_x(place), GSRybot + ticsize);
  1356.            (*t->move)(gsr_map_x(place), GSRytop);
  1357.            (*t->vector)(gsr_map_x(place), GSRytop - ticsize);
  1358.     } else {
  1359.            (*t->move)(gsr_map_x(place), GSRybot);
  1360.            (*t->vector)(gsr_map_x(place), GSRybot - ticsize);
  1361.     }
  1362.  
  1363.     /* label the ticmark */
  1364.     if (text) {
  1365.        (void) sprintf(ticlabel, text, CheckLog(GSRlogx, place));
  1366.        if ((*t->justify_text)(CENTRE)) {
  1367.           (*t->put_text)(gsr_map_x(place),
  1368.                       GSRybot-(t->v_char), ticlabel);
  1369.        } else {
  1370.           (*t->put_text)(gsr_map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1371.                       GSRybot-(t->v_char), ticlabel);
  1372.        }
  1373.     }
  1374. }
  1375.  
  1376. static int_error(str,t_num)
  1377. char str[];
  1378. int t_num;
  1379. /*
  1380.    Routine to print an error and die.  This is modified from the more
  1381.    complex gnuplot version which longjumps back to the gnuplot prompt.
  1382.    Note: NO_CARET is kept in some of the code above just to make these
  1383.    routines look more like the originals.  It isn't used at all here, 
  1384.    however.
  1385. */
  1386. {
  1387. /* t_num is the token number, we don't have tokens... */
  1388.      fprintf(stderr,"%s\n\n", str);
  1389.  
  1390. #ifdef MAYBE_LATER
  1391.     longjmp(env, TRUE);    /* bail out to command line */
  1392. #else
  1393.     exit(1);
  1394. #endif
  1395. }
  1396.